package org.example.springtest.annotation;

import org.junit.jupiter.api.Test;
import org.springframework.core.annotation.AnnotationUtils;

import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.*;

/**
 * <table border="1">
 *     <tr>
 *         <th>特性</th>
 *         <th>{@code findAnnotation}</th>
 *         <th>{@code getAnnotation}</th>
 *     </tr>
 *     <tr>
 *         <td>对{@code AliasFor}别名的支持</td>
 *         <td>✓</td>
 *         <td>✓</td>
 *     </tr>
 *     <tr>
 *         <td>对属性覆盖的支持</td>
 *         <td>✗</td>
 *         <td>✗</td>
 *     </tr>
 *     <tr>
 *         <td>直接存在的注解</td>
 *         <td>✓</td>
 *         <td>✓</td>
 *     </tr>
 *     <tr>
 *         <td>有{@code @Inherited}的类继承</td>
 *         <td>✓</td>
 *         <td>✓</td>
 *     </tr>
 *     <tr>
 *         <td>无{@code @Inherited}的类继承</td>
 *         <td>✓</td>
 *         <td>✗</td>
 *     </tr>
 *     <tr>
 *         <td>实现的接口类注解</td>
 *         <td>✓</td>
 *         <td>✗</td>
 *     </tr>
 *     <tr>
 *         <td>一层元注解</td>
 *         <td>✓</td>
 *         <td>✓</td>
 *     </tr>
 *     <tr>
 *         <td>多层元注解</td>
 *         <td>✓</td>
 *         <td>✗</td>
 *     </tr>
 *     <tr>
 *         <td>继承的方法注解</td>
 *         <td>✓</td>
 *         <td>✗</td>
 *     </tr>
 *     <tr>
 *         <td>实现的接口方法注解</td>
 *         <td>✓</td>
 *         <td>✗</td>
 *     </tr>
 * </table>
 *
 * @author yutianhong
 * @version 1.0
 * @see org.springframework.core.annotation.AnnotationUtils
 * @since 2025/4/3 10:57
 */
public class AnnotationUtilsTest {
    // 定义测试用注解
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Repeatable(Container.class)
    @interface TestAnnotation {
        String value() default "default";
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Inherited
    @interface InheritedAnnotation {
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    @interface MethodAnnotation {
        String value();
    }

    @Retention(RetentionPolicy.RUNTIME)
    @TestAnnotation("meta-test") // 单层元注解
    @interface ComposedAnnotation {
    }

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @interface Container {
        TestAnnotation[] value();
    }

    // 测试类层次结构
    @InheritedAnnotation
    @TestAnnotation("parent")
    static class Parent {
        @SuppressWarnings("unused") // used by java reflection
        @MethodAnnotation("parent-method")
        public void method() {
        }
    }

    static class Child extends Parent {
        @Override
        public void method() {
        } // 无注解
    }

    // 桥接方法测试
    @TestAnnotation("interface-class")
    interface Generic<T> {
        @TestAnnotation("interface-method")
        @MethodAnnotation("interface-method")
        void process(T t);
    }

    static class StringProcessor implements Generic<String> {
        @Override
        @MethodAnnotation("implement-method")
        public void process(String s) {
        }
    }

    // 元注解测试
    @ComposedAnnotation
    static class MetaAnnotatedClass {
    }

    // 重复注解测试
    @TestAnnotation("repeat1")
    @TestAnnotation("repeat2")
    static class RepeatedClass {
    }

    @TestExplicitAliases(a = "TestExplicitAliases")
    @TestImplicitAliases(a = "TestImplicitAliases")
    @TestTransitive(a = "TestTransitiveImplicitAliases")
    @TestImplicitOverrides(a = "TestImplicitOverrides")
    static class GeneralTestClass {
    }

    // 测试显式别名
    @Test
    public void testExplicitAliases() {
        TestExplicitAliases annotation = AnnotationUtils.getAnnotation(GeneralTestClass.class, TestExplicitAliases.class);
        assertNotNull(annotation);
        assertEquals("TestExplicitAliases", annotation.a());
        assertEquals("TestExplicitAliases", annotation.b());
        // 显式别名生效
    }

    // 测试隐式别名
    @Test
    public void testImplicitAliases() {
        TestImplicitAliases annotation = AnnotationUtils.getAnnotation(GeneralTestClass.class, TestImplicitAliases.class);
        assertNotNull(annotation);
        assertEquals("TestImplicitAliases", annotation.a());
        assertEquals("TestImplicitAliases", annotation.b());
        // 隐式别名生效
        TestImplicitAliasesMetaL1 meta = AnnotationUtils.getAnnotation(GeneralTestClass.class, TestImplicitAliasesMetaL1.class);
        assertNotNull(meta);
        assertEquals("default x from meta L1", meta.x());  // not equals to "TestImplicitAliases"
        // 无法显式覆盖
    }

    // 测试传递隐式别名
    @Test
    public void testTransitiveImplicitAliases() {
        TestTransitive annotation = AnnotationUtils.getAnnotation(GeneralTestClass.class, TestTransitive.class);
        assertNotNull(annotation);
        assertEquals("TestTransitiveImplicitAliases", annotation.a());
        assertEquals("TestTransitiveImplicitAliases", annotation.b());
        // 传递隐式别名生效

        TestTransitiveMetaL1 metaL1 = AnnotationUtils.getAnnotation(GeneralTestClass.class, TestTransitiveMetaL1.class);
        assertNotNull(metaL1);
        assertEquals("default x from meta L1", metaL1.x());  // not equals to "TestTransitiveImplicitAliases"
        // 无法显式覆盖

        TestTransitiveMetaL2 metaL2;
        metaL2 = AnnotationUtils.getAnnotation(GeneralTestClass.class, TestTransitiveMetaL2.class);
        assertNull(metaL2); // 不支持多层元注解
        metaL2 = AnnotationUtils.findAnnotation(GeneralTestClass.class, TestTransitiveMetaL2.class);
        assertNotNull(metaL2);
        assertEquals("default y from meta L2", metaL2.y());  // not equals to "TestTransitiveImplicitAliases"
        // 无法传递显式覆盖
    }

    // 测试隐式覆盖
    @Test
    public void testImplicitOverrides() {
        TestImplicitOverrides annotation = AnnotationUtils.getAnnotation(GeneralTestClass.class, TestImplicitOverrides.class);
        assertNotNull(annotation);
        assertEquals("TestImplicitOverrides", annotation.a());

        TestImplicitOverridesMetaL1 metaL1 = AnnotationUtils.getAnnotation(GeneralTestClass.class, TestImplicitOverridesMetaL1.class);
        assertNotNull(metaL1);
        assertEquals("default a from meta L1", metaL1.a()); // not equals to "TestImplicitOverrides"
        // 无法隐式覆盖
    }

    // 测试继承链中的注解查找
    @Test
    void testFindAnnotation_OnClassWithInheritance() {
        TestAnnotation ann = AnnotationUtils.findAnnotation(Child.class, TestAnnotation.class);
        assertNotNull(ann);
        assertEquals("parent", ann.value());    // 继承父类的 没有@Inherited标注的注解
    }

    // 测试接口实现链中的注解查找
    @Test
    void testFindAnnotation_OnClassWithInterfaceInheritance() {
        TestAnnotation ann = AnnotationUtils.findAnnotation(StringProcessor.class, TestAnnotation.class);
        assertNotNull(ann);
        assertEquals("interface-class", ann.value());    // 从接口获取的 没有@Inherited标注的注解
    }

    // 测试方法注解继承
    @Test
    void testFindAnnotation_OnOverriddenMethod() throws Exception {
        Method childMethod = Child.class.getMethod("method");
        MethodAnnotation ann = AnnotationUtils.findAnnotation(childMethod, MethodAnnotation.class);
        assertNotNull(ann); // 继承父类方法注解
        assertEquals("parent-method", ann.value());
    }

    // 桥接方法处理测试
    @Test
    void testFindAnnotation_HandleBridgeMethod() throws Exception {
        Method bridgeMethod = StringProcessor.class.getMethod("process", Object.class);
        TestAnnotation ann = AnnotationUtils.findAnnotation(bridgeMethod, TestAnnotation.class);
        assertNotNull(ann);
        assertEquals("interface-method", ann.value()); // 查找接口方法上的注解

        MethodAnnotation annotation = AnnotationUtils.findAnnotation(bridgeMethod, MethodAnnotation.class);
        assertNotNull(annotation);
        assertEquals("implement-method", annotation.value());   // 优先获取当前实现类上的注解
    }

    // 单层元注解支持测试
    @Test
    void testFindAnnotation_FindMetaAnnotation() {
        TestAnnotation ann = AnnotationUtils.findAnnotation(MetaAnnotatedClass.class, TestAnnotation.class);
        assertNotNull(ann); // AnnotationUtils递归搜索元注解
    }

    // 边界条件：不存在的注解
    @Test
    void testFindAnnotation_FindNonExistentAnnotation() {
        SuppressWarnings annotation = AnnotationUtils.findAnnotation(Child.class, SuppressWarnings.class);
        assertNull(annotation); // 返回null值，不报错
    }

    // 测试直接获取注解
    @Test
    void testGetAnnotation_getInheritedAnnotation() {
        TestAnnotation testAnnotation = AnnotationUtils.getAnnotation(Child.class, TestAnnotation.class);
        assertNull(testAnnotation); // 没有@Inherited标注，无法获取

        InheritedAnnotation inheritedAnnotation = AnnotationUtils.getAnnotation(Child.class, InheritedAnnotation.class);
        assertNotNull(inheritedAnnotation); // 有@Inherited标注，可以获取
        // 和JDK的API效果类似
    }

    // 默认值处理测试
    @Test
    void testGetDefaultValue() {
        Object defaultValue = AnnotationUtils.getDefaultValue(TestAnnotation.class, "value");
        assertEquals("default", defaultValue);
    }

    // 重复注解处理（需要容器注解）
    @Test
    void testGetRepeatableAnnotations() {
        @SuppressWarnings("deprecation")    // only for unit test
        Set<TestAnnotation> anns = AnnotationUtils.getRepeatableAnnotations(
                RepeatedClass.class, TestAnnotation.class, Container.class
        );
        assertEquals(2, anns.size());
    }

    // 清除缓存测试
    @Test
    void testClearCache() {
        // 初次查找
        TestAnnotation ann1 = AnnotationUtils.findAnnotation(Child.class, TestAnnotation.class);
        // 清空缓存
        AnnotationUtils.clearCache();
        // 再次查找
        TestAnnotation ann2 = AnnotationUtils.findAnnotation(Child.class, TestAnnotation.class);
        assertNotSame(ann1, ann2);
    }

    // 测试获取注解属性
    @Test
    void testGetAnnotationAttributes() {
        TestAnnotation ann = AnnotationUtils.findAnnotation(Parent.class, TestAnnotation.class);
        assertNotNull(ann);
        Map<String, Object> attrs = AnnotationUtils.getAnnotationAttributes(ann);
        assertEquals(Collections.singletonMap("value", "parent"), attrs);
    }

}
